package arith;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CharStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.TokenStream;
import org.antlr.runtime.tree.CommonTreeNodeStream;

import arith.BasicArithmeticEquParser.evaluator_return;
import arith.BasicArithmeticEquParser.problem_return;

public class ArithServer2 {

		public static final int PORT = 8887;
		
		public static void main(String args[]){
			new ArithServer2().doIt();
		}
		
		public void doIt(){
			String userInput = "";
			try{
				ServerSocket ss = new ServerSocket(PORT);
				while(true){
					Socket sock = ss.accept();
					BufferedReader in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
					userInput = in.readLine();
					System.out.println(userInput);
					OutputStreamWriter out = new OutputStreamWriter(sock.getOutputStream());
					//ObjectOutputStream out = new ObjectOutputStream(sock.getOutputStream());
					BufferedWriter bw = new BufferedWriter(out);
					//Problem prob = runTest(new Problem(userInput));
					bw.write(runTest(new Problem(userInput)).getProblem() + "\n");
					bw.flush();
					//Problem p = runTest(userInput);
					//System.out.println(p);
					//out.writeObject(p);
					
					//out.flush();
				}
			}catch(Exception e){
				e.printStackTrace();
				System.out.println("Cannot connect to server");
			}
		}

		public Problem runTest(Problem prob) throws RecognitionException{
			//Parse prob's template and problem
			String equ = prob.getTemplate();
			CharStream charStream = new ANTLRStringStream(equ);
			BasicArithmeticEquLexer lexer = new BasicArithmeticEquLexer(charStream);
			TokenStream tokenStream = new CommonTokenStream(lexer);
			BasicArithmeticEquParser parser = new BasicArithmeticEquParser(tokenStream);
			evaluator_return evaluator = parser.evaluator();
			CommonTreeNodeStream nodeStream = new CommonTreeNodeStream(evaluator.tree);
			GrammarEvaluator walker = new GrammarEvaluator(nodeStream);
			
			//Prints out the tree
			//System.out.println(evaluator.tree.toStringTree());
			
			//The result of the expression
			Output result = walker.evaluator();
			
			if(result == null){
				System.out.println("result is null");
			}
		    if(result.id == 0){
		    	//Solution is a double
		    	prob.setProblem(result.nSolution.prob);
		    	prob.setSolution(result.nSolution.number);
		    }else if(result.id == 1){
		    	//Solution is a fraction
		    	prob.setProblem(result.fSolution.prob);
		    	prob.setSolution(result.fSolution);
		    }else if(result.id == 2){
		    	//Solution is an exponent
		    	prob.setProblem(result.eSolution.prob);
		    	prob.setSolution(result.eSolution);
		    }else if(result.id == 3){
		    	//Solution is a list of factors or a single int
		    	prob.setProblem(result.factorSolution.prob.getProblem());
		    	prob.setSolution(result.factorSolution.factors);
		    }else if(result.id == 4){
		    	//Solution is a string
		    	prob.setProblem(result.propSolution.prob.getProblem());
		    	prob.setSolution(result.propSolution.prob.stringSolution);
		    }else if(result.id == 5){
		    	//Solution is a polynomial
		    	prob.setProblem(result.polySolution.toString());
		    	prob.setSolution(result.polySolution);
		    }else{
		    	prob = null;
		    }
		    
		    //Print out the problem
		    //System.out.println(prob.toString());
		    
		    //Print out the MathML of the problem
		    //System.out.println("MathML:" + makeImage(prob));
		    return prob;
		    
		}
		
		public Problem runTest(String equ) throws RecognitionException{
			CharStream charStream = new ANTLRStringStream(equ);
			BasicArithmeticEquLexer lexer = new BasicArithmeticEquLexer(charStream);
			TokenStream tokenStream = new CommonTokenStream(lexer);
			BasicArithmeticEquParser parser = new BasicArithmeticEquParser(tokenStream);
			problem_return problem;
			problem = parser.problem();
			CommonTreeNodeStream nodeStream = new CommonTreeNodeStream(problem.tree);
			GrammarEvaluator walker = new GrammarEvaluator(nodeStream);
			Problem prob = walker.problem();
			return runTest(prob);
		}
}